package web;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.xml.bind.JAXBException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import web.opodoElements.AirSearchResponse;
import web.opodoElements.FareBreakDown;
import web.opodoElements.FareBreakDowns;
import web.opodoElements.FlightRecommendation;
import web.opodoElements.FlightRecommendationGroup;
import web.opodoElements.Leg;
import web.opodoElements.Proposal;
import web.opodoElements.Segment;

public class Populate implements Runnable {
	String iataDep;
	String iataArriv;
	String year;
	String month;
	String day;
	//HttpURLConnection conn; // The actual connection to the web page
	java.sql.Connection con;
	String query=null;
	List <CompleteFlightInfo> completeFlightInfos=new ArrayList<CompleteFlightInfo>();
	int rsU=0;
	int tentativi;
	long port = 0;
	DateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH);
	//Trasformo la date in un formato accettabile per mysql
	java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.ITALY);
	HttpGet get;
	HttpClient client;
	HttpContext context;

	public Populate(String iataDep, String iataArriv,String year, String month, String day, java.sql.Statement st, java.sql.Connection con,int tentativi, HttpGet get, HttpClient client) {
		this.iataDep=iataDep;
		this.iataArriv=iataArriv;
		this.year=year;
		this.month=month;
		this.day=day;
		this.con=con;
		this.tentativi=tentativi;
		this.get=get;
		this.client=client;
		this.context = new BasicHttpContext();
		//this.conn=conn;
		if(month.length()==1){
			String tmp = "0";
			this.month = tmp.concat(month);
		}
	}

	public void run(){
		String urlToRead="http://xml.opodo.it/opodo/flights/simpleXml?departureMonth="+year+""+month+"&departureDay="+day+"&departureTime=ANY&departureAirportCode="+iataDep+"&numberOfChildren=0&tripType=O&reset=true&arrivalAirportCode="+iataArriv+"&numberOfAdults=1&numberOfInfants=0&locale=it_IT&directFlight=true&searchLowCost=true";
		//		String urlToRead="http://www.opodo.co.uk/opodo/flights/simpleXml?reset=true&departureAirportCode=lon&arrivalAirportCode=mad&Type=R&departureDay=10&departureMonth=201107&departureTime=ANY&returnDay=17&returnMonth=201107&returnTime=ANY&numberOfAdults=1&numberOfChildren=0&numberOfInfants=0&searchLowCost=true";
		//		System.out.println(urlToRead);
		//		System.out.print(iataDep+" "+iataArriv+"\n");
		URL url; // The URL to read
		BufferedReader rd; // Used to read results from the web page
		String line; // An individual line of the web page HTML
		String xml = ""; // A long string containing all the HTML
		try {
			//------DEBUG OUTPUT----------
//			System.out.println(iataDep+" "+iataArriv+" "+day+" "+month+" "+year+" "+urlToRead);
			//----------------------------
			url = new URL(urlToRead);
			this.get.setURI(url.toURI());
			HttpResponse response = this.client.execute(this.get, this.context);
			HttpEntity entity = response.getEntity();
			//conn = (HttpURLConnection) url.openConnection();
			//conn.setRequestMethod("GET");
			rd = new BufferedReader(new InputStreamReader(entity.getContent()));

			while ((line = rd.readLine()) != null) {
				xml += line;
			}
			rd.close();
			EntityUtils.consume(entity);
		} catch (Exception e) {		
//			System.out.println("#######################Tentativo "+tentativi+" Fallito#########################");
//			//IN CASO DI TIMEOUT RIPROVO LANCIO UN THREAD RICORSIVO FINO A 10 VOLTE
//			tentativi++;
//			try {
//				Thread.sleep(100);
//			} catch (InterruptedException e1) {
//				// TODO Auto-generated catch block
//				e1.printStackTrace();
//			}
//			if(tentativi<11)new Thread(new Populate(iataDep,iataArriv,year,month,day,st,con,tentativi,this.get,this.client)).start();
//			else{
////				System.out.println("##############################################################");
				System.out.println("#######################Niente da fare#########################");
//				System.out.println("##############################################################");
				System.out.println("##### "+urlToRead);
//
//			}
			return;
		}

		UnmarshallerOpodo opodo = new UnmarshallerOpodo();
		AirSearchResponse airSearchResponse=null;
		try {
			airSearchResponse = opodo.fromXmlToClasses(xml);
		} catch (JAXBException e) {
			// TODO Auto-generated catch block
			System.out.println("#######################Problemi Jaxb legati al timeout#########################");
			return;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println("#######################Problemi di rete#########################");
			return;
		}
		if(airSearchResponse==null)
			return;
		String status=airSearchResponse.getStatus();
		//System.out.print("Status: " + status + "\n");
		if(status.contentEquals("success")){
			List<Proposal> proposal = airSearchResponse.getItineries().getProposal();
			//Per ogni proposal
			for (Proposal p : proposal) {
				List<Leg> leg = p.getLegs().getLeg();
				//Per ogni leg
				for (Leg l : leg) {
					completeFlightInfos.add(new CompleteFlightInfo());
					//System.out.print("Leg: " + leg.indexOf(l) + ": " + l.getId());
					completeFlightInfos.get(completeFlightInfos.size()-1).setOpodoCode(l.getId());
					//System.out.print(" D: " + l.getDuration());
					completeFlightInfos.get(completeFlightInfos.size()-1).setDurata(l.getDuration());
					List<Segment> segment= l.getSegments().getSegment();
					//Per tutti i segmenti, nel mio caso ho un solo segmento per ogni leg perch� guardo solo voli diretti
					for (Segment s : segment) {
						//System.out.print(" Volo: " + s.getFlightNumber());
						completeFlightInfos.get(completeFlightInfos.size()-1).setCodVolo(s.getFlightNumber());
						//System.out.print(" P: " + s.getNumAvailableSeats());
						completeFlightInfos.get(completeFlightInfos.size()-1).setPosti(s.getNumAvailableSeats());
						//System.out.print(" Classe: " + s.getCabin().getClasse());
						completeFlightInfos.get(completeFlightInfos.size()-1).setClasse(s.getCabin().getClasse());
						//System.out.print(" Da: " + s.getDepartureAirport().getIataCode() +" "+ s.getDepartureAirport().getCity().getIsoCode() +" "+ s.getDepartureAirport().getCountry().getIsoCode());
						completeFlightInfos.get(completeFlightInfos.size()-1).setAereoportoPartenza(s.getDepartureAirport().getIataCode());
						completeFlightInfos.get(completeFlightInfos.size()-1).setCittaPartenza(s.getDepartureAirport().getCity().getIsoCode());
						completeFlightInfos.get(completeFlightInfos.size()-1).setStatoPartenza(s.getDepartureAirport().getCountry().getIsoCode());
						//System.out.print(" A: " + s.getArrivalAirport().getIataCode() +" "+ s.getArrivalAirport().getCity().getIsoCode() +" "+ s.getArrivalAirport().getCountry().getIsoCode());
						completeFlightInfos.get(completeFlightInfos.size()-1).setAereoportoArrivo(s.getArrivalAirport().getIataCode());
						completeFlightInfos.get(completeFlightInfos.size()-1).setCittaArrivo(s.getArrivalAirport().getCity().getIsoCode());
						completeFlightInfos.get(completeFlightInfos.size()-1).setStatoArrivo(s.getArrivalAirport().getCountry().getIsoCode());
						//System.out.print(" Partenza: " + s.getOutboundDate());
						try {
							completeFlightInfos.get(completeFlightInfos.size()-1).setPartenza(formatter.parse(s.getOutboundDate()));
						} catch (ParseException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
							return;
						}
						//System.out.print(" Arrivo: " + s.getInboundDate());
						try {
							completeFlightInfos.get(completeFlightInfos.size()-1).setArrivo(formatter.parse(s.getInboundDate()));
						} catch (ParseException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
							return;
						}
						//System.out.print(" Compagnia: " + s.getCarrierInformation().getMarketingCarrier().getIataCode() +" "+ s.getCarrierInformation().getMarketingCarrier().getName()+ "\n");
						completeFlightInfos.get(completeFlightInfos.size()-1).setCodCompagnia(s.getCarrierInformation().getMarketingCarrier().getIataCode());			
						completeFlightInfos.get(completeFlightInfos.size()-1).setCompagnia(s.getCarrierInformation().getMarketingCarrier().getName());	
						completeFlightInfos.get(completeFlightInfos.size()-1).setOperatore("OP");	

					}	
				}
			}
			List <FlightRecommendationGroup> flightRecommendationGroup=airSearchResponse.getRecommendations().getFlightRecommendationGroups().getFlightRecommendationGroup();
			for (FlightRecommendationGroup f : flightRecommendationGroup) {
				for (CompleteFlightInfo comp : completeFlightInfos) {
					List<FlightRecommendation> f1=f.getFlightRecommendation();
					for(FlightRecommendation f2: f1){
						//Ho solo voli diretti quindi ho solo una leg
						List<Leg> l1= f2.getLeg();
						if(comp.getOpodoCode().equals(l1.get(0).getLegID())){
							//Se esistono dettagli sulle tasse leggili
							FareBreakDowns f3=f.getFareBreakDowns();
							List<FareBreakDown> f4=f3.getFareBreakDown();
							if(f3.getFareBreakDown()!=null)comp.setTasse(Float.valueOf(f4.get(0).getTaxes().getAmount()).floatValue());
							comp.setPrezzo(Float.valueOf(f.getTotalPrice().getAmount()).floatValue());
							break;
						}
					}
				}
			}
		}

		//Ho Formattato correttamente la classe Complete flight info, ora aggiorno il db

		//QUesta operazione � da eseguire una volta al mese assieme a tutte le combinazioni possibili perch� aggiorno aereoporti e citt�. quotidianamente basta meno
		for (CompleteFlightInfo fine : completeFlightInfos) {
			//System.out.println("Resoconto");
			//System.out.println(fine.resoconto());
			String updateQuery="";
			ResultSet rs= null;
			java.sql.PreparedStatement pSt= null;
			try {
				//Stati nuovi
				query="select * from nazioni where idNazioni=?";
				pSt = con.prepareStatement(query);		
				pSt.setString(1,fine.getStatoPartenza());
				rs=pSt.executeQuery();
				//System.out.println(rs.next());
				//Se sono aereoporti sconosciuti
				if (!rs.first()) {
					query="insert into nazioni values(?,null)";
					pSt = con.prepareStatement(query);
					pSt.setString(1,fine.getStatoPartenza());
					rsU=pSt.executeUpdate();
				}
				//Citt� nuove
				query="select * from citta where idCitta=?";
				pSt = con.prepareStatement(query);		
				pSt.setString(1,fine.getCittaPartenza());
				rs=pSt.executeQuery();
				//Se sono aereoporti sconosciuti
				//System.out.println(rs.first());
				if (!rs.first()) {
					query="insert into citta values(?,null,?)";
					pSt = con.prepareStatement(query);
					pSt.setString(1,fine.getCittaPartenza());
					pSt.setString(2,fine.getStatoPartenza());
					rsU=pSt.executeUpdate();
				}
				//Aereoporti nuovi
				query="select * from aereoporti where idAereoporto=?";
				pSt = con.prepareStatement(query);		
				pSt.setString(1,fine.getAereoportoPartenza());
				rs=pSt.executeQuery();
				//Se sono aereoporti sconosciuti
				if (!rs.first()) {
					query="insert into aereoporti values(?,null,?)";
					pSt = con.prepareStatement(query);
					pSt.setString(1,fine.getAereoportoPartenza());
					pSt.setString(2,fine.getCittaPartenza());
					rsU=pSt.executeUpdate();
				}
				/////////////////////////////////////PARAMETRI ARRIVO
				//Stati nuovi
				query="select * from nazioni where idNazioni=?";
				pSt = con.prepareStatement(query);		
				pSt.setString(1,fine.getStatoArrivo());
				rs=pSt.executeQuery();
				//System.out.println(rs.next());
				//Se sono aereoporti sconosciuti
				if (!rs.first()) {
					query="insert into nazioni values(?,null)";
					pSt = con.prepareStatement(query);
					pSt.setString(1,fine.getStatoArrivo());
					rsU=pSt.executeUpdate();
				}
				//Citt� nuove
				query="select * from citta where idCitta=?";
				pSt = con.prepareStatement(query);		
				pSt.setString(1,fine.getCittaArrivo());
				rs=pSt.executeQuery();
				//Se sono aereoporti sconosciuti

				if (!rs.first()) {
					query="insert into citta values(?,null,?)";
					pSt = con.prepareStatement(query);
					pSt.setString(1,fine.getCittaArrivo());
					pSt.setString(2,fine.getStatoArrivo());
					rsU=pSt.executeUpdate();
				}
				//Aereoporti nuovi
				query="select * from aereoporti where idAereoporto=?";
				pSt = con.prepareStatement(query);		
				pSt.setString(1,fine.getAereoportoArrivo());
				rs=pSt.executeQuery();
				//Se sono aereoporti sconosciuti
				if (!rs.first()) {
					query="insert into aereoporti values(?,null,?)";
					pSt = con.prepareStatement(query);
					pSt.setString(1,fine.getAereoportoArrivo());
					pSt.setString(2,fine.getCittaArrivo());
					rsU=pSt.executeUpdate();
				}
				//Compagnia
				query="select * from Compagnia where idCompagnia=?";
				pSt = con.prepareStatement(query);		
				pSt.setString(1,fine.getCodCompagnia());
				rs=pSt.executeQuery();
				//Se � una compagnia sconosciuta
				if (!rs.first()) {
					query="insert into Compagnia values(?,?)";
					pSt = con.prepareStatement(query);
					pSt.setString(1,fine.getCodCompagnia());
					pSt.setString(2,fine.getCompagnia());
					rsU=pSt.executeUpdate();
				}

				//Volo
				
				query="select * from voli where id=? and compagnia=? and oraP=?";
				pSt = con.prepareStatement(query);		
				pSt.setInt(1,fine.getCodVolo());
				pSt.setString(2,fine.getCodCompagnia());
				pSt.setString(3, sdf.format(fine.getPartenza()));
				rs=pSt.executeQuery();
				//Se sono aereoporti sconosciuti
				if (!rs.first()) {
					query="insert into voli values(?,?,?,?,?,?,?,?,?,?,?,?,default)" ;
//								+"on duplicate key update prezzo=?, tasse=?, posti=?, time_insert=now();";
					pSt = con.prepareStatement(query);
					pSt.setInt(1,fine.getCodVolo());
					pSt.setString(2,fine.getCodCompagnia());
					pSt.setString(3,fine.getAereoportoPartenza());
					pSt.setString(4,fine.getAereoportoArrivo());
					pSt.setString(5,sdf.format( fine.getPartenza()));
					pSt.setString(6,sdf.format(fine.getArrivo()));
					pSt.setInt(7,fine.getDurata());
					pSt.setString(8,"OP");
					pSt.setInt(9,fine.getPosti());
					pSt.setString(10, fine.getClasse());
					pSt.setFloat(11, fine.getPrezzo());
					pSt.setFloat(12, fine.getTasse());
//					pSt.setFloat(13, fine.getPrezzo());
//					pSt.setFloat(14, fine.getTasse());
//					pSt.setInt(15,fine.getPosti());
					updateQuery="INSERT: "+pSt.toString();
					try{
						rsU=pSt.executeUpdate();
					} catch (Exception e){
						System.out.println("Exception in: "+updateQuery);
						return;
					}
				} else {
					query="update voli set posti=?, prezzo=?, tasse=?, time_insert=now() where id=? and compagnia=? and oraP=? and classe=?";
					pSt = con.prepareStatement(query);
					pSt.setInt(1,fine.getPosti());
					pSt.setFloat(2, fine.getPrezzo());
					pSt.setFloat(3, fine.getTasse());
					pSt.setInt(4,fine.getCodVolo());
					pSt.setString(5,fine.getCodCompagnia());
					pSt.setString(6,sdf.format( fine.getPartenza()));
					pSt.setString(7, fine.getClasse());
					updateQuery="UPDATE: "+pSt.toString();
					try{
						rsU=pSt.executeUpdate();
					} catch (Exception e){
						System.out.println("Exception in: "+updateQuery);
						return;
					}
				}
				rs.close();
			} catch (SQLException e) {
				System.err.println("Populate: Error while executing DB update @354");
				e.printStackTrace();
			} finally {
				try {
					pSt.close();
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			} 
		}
		return;
	}







}
